package com.sunnfun.handler;

import com.sunnfun.model.RpcRequest;
import com.sunnfun.model.RpcResponse;
import com.sunnfun.registry.LocalRegistry;
import com.sunnfun.serializer.JdkSerializer;
import com.sunnfun.serializer.Serializer;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.*;
import io.netty.util.CharsetUtil;

import java.io.IOException;
import java.lang.reflect.Method;

/**
 * Netty HTTP 请求处理器
 */
@ChannelHandler.Sharable
public class NettyHttpServerHandler extends SimpleChannelInboundHandler<FullHttpRequest> {

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, FullHttpRequest request) {
        // 指定序列化器
        final Serializer serializer = new JdkSerializer();

        // 记录日志
        System.out.println("Received request: " + request.method() + " " + request.uri());

        // 读取请求体
        byte[] requestBody = new byte[request.content().readableBytes()];
        request.content().readBytes(requestBody);

        // 反序列化得到 RpcRequest
        RpcRequest rpcRequest;
        try {
            rpcRequest = serializer.deserialize(requestBody, RpcRequest.class);
        } catch (Exception e) {
            e.printStackTrace();
            // 如果反序列化失败，返回错误信息
            RpcResponse errorResponse = new RpcResponse();
            errorResponse.setMessage("Failed to deserialize request: " + e.getMessage());
            doResponse(ctx, request, errorResponse, serializer);
            return;
        }

        // 如果 rpcRequest 为空，直接返回
        if (rpcRequest == null) {
            RpcResponse errorResponse = new RpcResponse();
            errorResponse.setMessage("rpcRequest is null");
            doResponse(ctx, request, errorResponse, serializer);
            return;
        }

        // 构造响应结果
        RpcResponse rpcResponse = new RpcResponse();
        try {
            // 根据 serviceName 从本地注册中心拿实现类
            Class<?> implClass = LocalRegistry.get(rpcRequest.getServiceName());
            if (implClass == null) {
                throw new RuntimeException("No implementation found for service: " + rpcRequest.getServiceName());
            }

            // 通过反射调用目标方法
            Method method = implClass.getMethod(rpcRequest.getMethodName(), rpcRequest.getParameterTypes());
            Object result = method.invoke(implClass.newInstance(), rpcRequest.getArgs());

            // 封装返回结果
            rpcResponse.setMessage("ok");
            rpcResponse.setData(result);
            rpcResponse.setDataType(method.getReturnType());

        } catch (Exception e) {
            e.printStackTrace();
            rpcResponse.setMessage("Invoke target method error: " + e.getMessage());
            rpcResponse.setException(e);
        }

        // 返回给客户端
        doResponse(ctx, request, rpcResponse, serializer);
    }

    /**
     * 将响应对象序列化并通过 Netty 写回客户端
     */
    private void doResponse(ChannelHandlerContext ctx, FullHttpRequest request,
                            RpcResponse rpcResponse, Serializer serializer) {
        byte[] responseBytes;
        try {
            responseBytes = serializer.serialize(rpcResponse);
        } catch (IOException e) {
            e.printStackTrace();
            responseBytes = ("Failed to serialize response: " + e.getMessage())
                    .getBytes(CharsetUtil.UTF_8);
        }

        // 构造 FullHttpResponse
        FullHttpResponse response = new DefaultFullHttpResponse(
                HttpVersion.HTTP_1_1,
                HttpResponseStatus.OK,
                Unpooled.wrappedBuffer(responseBytes)
        );
        response.headers().set(HttpHeaderNames.CONTENT_TYPE, "application/json");
        response.headers().set(HttpHeaderNames.CONTENT_LENGTH, responseBytes.length);

        // 如果是 Keep-Alive 请求，需要设置 CONNECTION: keep-alive
        if (HttpUtil.isKeepAlive(request)) {
            response.headers().set(HttpHeaderNames.CONNECTION, HttpHeaderValues.KEEP_ALIVE);
        }

        // 写回并刷新至客户端
        ctx.writeAndFlush(response);
    }
}